"""
配置管理模块

负责加载和管理应用程序配置
"""

import os
import json
from pathlib import Path
from typing import Any, Dict, Optional, List, Union

import yaml
from pydantic import BaseModel, Field, validator
from dotenv import load_dotenv

from .encryption import ConfigEncryption, decrypt_sensitive_value


class ProxyConfig(BaseModel):
    """代理配置"""
    enabled: bool = Field(default=False, description="是否启用代理")
    type: str = Field(default="socks5", description="代理类型: socks5 或 http")
    host: str = Field(default="127.0.0.1", description="代理主机")
    port: int = Field(default=10801, description="代理端口")
    
    @validator('type')
    def validate_proxy_type(cls, v):
        if v not in ['socks5', 'http', 'https']:
            raise ValueError('代理类型必须是 socks5, http 或 https')
        return v
    
    @validator('port')
    def validate_port(cls, v):
        if not 1 <= v <= 65535:
            raise ValueError('端口号必须在 1-65535 范围内')
        return v


class BrowserConfig(BaseModel):
    """浏览器配置"""
    headless: bool = Field(default=False, description="是否无头模式")
    timeout: int = Field(default=30000, description="超时时间(毫秒)")
    user_agent: str = Field(
        default="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        description="用户代理字符串"
    )
    args: List[str] = Field(
        default_factory=lambda: [
            "--no-sandbox",
            "--disable-dev-shm-usage",
            "--disable-blink-features=AutomationControlled"
        ],
        description="浏览器启动参数"
    )
    proxy: ProxyConfig = Field(default_factory=ProxyConfig, description="代理配置")
    
    @validator('timeout')
    def validate_timeout(cls, v):
        if v < 1000:
            raise ValueError('超时时间不能少于1000毫秒')
        return v


class AIModelConfig(BaseModel):
    """AI模型配置"""
    text: str = Field(default="Qwen/Qwen2.5-72B-Instruct", description="文本模型")
    vision: str = Field(default="Qwen/Qwen2.5-VL-72B-Instruct", description="视觉模型")


class AIConfig(BaseModel):
    """AI服务配置"""
    api_key: str = Field(description="API密钥")
    base_url: str = Field(default="https://api.siliconflow.cn/v1", description="API基础URL")
    model: AIModelConfig = Field(default_factory=AIModelConfig, description="模型配置")
    timeout: int = Field(default=30, description="请求超时时间(秒)")
    max_retries: int = Field(default=3, description="最大重试次数")
    
    @validator('timeout')
    def validate_timeout(cls, v):
        if v < 1:
            raise ValueError('超时时间不能少于1秒')
        return v
    
    @validator('max_retries')
    def validate_max_retries(cls, v):
        if v < 0:
            raise ValueError('最大重试次数不能为负数')
        return v


class LoggingConfig(BaseModel):
    """日志配置"""
    level: str = Field(default="INFO", description="日志级别")
    file: str = Field(default="logs/gamer520.log", description="日志文件路径")
    max_size: str = Field(default="10MB", description="日志文件最大大小")
    backup_count: int = Field(default=5, description="日志文件备份数量")
    format: str = Field(
        default="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        description="日志格式"
    )
    date_format: str = Field(default="%Y-%m-%d %H:%M:%S", description="日期格式")
    
    @validator('level')
    def validate_level(cls, v):
        valid_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
        if v.upper() not in valid_levels:
            raise ValueError(f'日志级别必须是 {valid_levels} 之一')
        return v.upper()
    
    @validator('backup_count')
    def validate_backup_count(cls, v):
        if v < 0:
            raise ValueError('备份数量不能为负数')
        return v


class BaiduAuthConfig(BaseModel):
    """百度网盘认证配置"""
    login_url: str = Field(default="https://pan.baidu.com", description="百度网盘登录URL")
    session_file: str = Field(default="data/baidu_session.json", description="会话文件路径")
    session_expire_days: int = Field(default=7, description="会话过期天数")
    login_timeout: int = Field(default=300, description="登录超时时间(秒)")
    check_interval: int = Field(default=3, description="登录状态检查间隔(秒)")
    auto_save_session: bool = Field(default=True, description="是否自动保存会话")
    
    @validator('session_expire_days')
    def validate_session_expire_days(cls, v):
        if v < 1:
            raise ValueError('会话过期天数不能少于1天')
        return v
    
    @validator('login_timeout')
    def validate_login_timeout(cls, v):
        if v < 30:
            raise ValueError('登录超时时间不能少于30秒')
        return v
    
    @validator('check_interval')
    def validate_check_interval(cls, v):
        if v < 1:
            raise ValueError('检查间隔不能少于1秒')
        return v


class TargetsConfig(BaseModel):
    """目标网站配置"""
    base_url: str = Field(default="https://www.gamer520.com/73454.html", description="基础URL")
    baidu_pan_url: str = Field(default="https://pan.baidu.com", description="百度网盘URL")
    timeout: int = Field(default=30, description="请求超时时间(秒)")
    retry_count: int = Field(default=3, description="重试次数")
    
    @validator('timeout')
    def validate_timeout(cls, v):
        if v < 1:
            raise ValueError('超时时间不能少于1秒')
        return v
    
    @validator('retry_count')
    def validate_retry_count(cls, v):
        if v < 0:
            raise ValueError('重试次数不能为负数')
        return v


class SecurityConfig(BaseModel):
    """安全配置"""
    encryption_enabled: bool = Field(default=False, description="是否启用加密")
    encryption_password: Optional[str] = Field(default=None, description="加密密码")
    api_rate_limit: int = Field(default=60, description="API速率限制(每分钟)")
    max_concurrent_requests: int = Field(default=5, description="最大并发请求数")
    
    @validator('api_rate_limit')
    def validate_api_rate_limit(cls, v):
        if v < 1:
            raise ValueError('API速率限制不能少于1')
        return v
    
    @validator('max_concurrent_requests')
    def validate_max_concurrent_requests(cls, v):
        if v < 1:
            raise ValueError('最大并发请求数不能少于1')
        return v


class PerformanceConfig(BaseModel):
    """性能配置"""
    page_load_timeout: int = Field(default=30000, description="页面加载超时时间(毫秒)")
    element_wait_timeout: int = Field(default=10000, description="元素等待超时时间(毫秒)")
    screenshot_quality: int = Field(default=80, description="截图质量(1-100)")
    cache_enabled: bool = Field(default=True, description="是否启用缓存")
    cache_size: int = Field(default=100, description="缓存大小")
    
    @validator('page_load_timeout')
    def validate_page_load_timeout(cls, v):
        if v < 1000:
            raise ValueError('页面加载超时时间不能少于1000毫秒')
        return v
    
    @validator('element_wait_timeout')
    def validate_element_wait_timeout(cls, v):
        if v < 1000:
            raise ValueError('元素等待超时时间不能少于1000毫秒')
        return v
    
    @validator('screenshot_quality')
    def validate_screenshot_quality(cls, v):
        if not 1 <= v <= 100:
            raise ValueError('截图质量必须在1-100范围内')
        return v
    
    @validator('cache_size')
    def validate_cache_size(cls, v):
        if v < 0:
            raise ValueError('缓存大小不能为负数')
        return v


class AppConfig(BaseModel):
    """应用程序配置"""
    browser: BrowserConfig = Field(default_factory=BrowserConfig, description="浏览器配置")
    ai: AIConfig = Field(description="AI服务配置")
    logging: LoggingConfig = Field(default_factory=LoggingConfig, description="日志配置")
    targets: TargetsConfig = Field(default_factory=TargetsConfig, description="目标网站配置")
    security: SecurityConfig = Field(default_factory=SecurityConfig, description="安全配置")
    performance: PerformanceConfig = Field(default_factory=PerformanceConfig, description="性能配置")
    baidu_auth: BaiduAuthConfig = Field(default_factory=BaiduAuthConfig, description="百度网盘认证配置")
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return self.dict()
    
    def to_json(self, indent: int = 2) -> str:
        """转换为JSON字符串"""
        return json.dumps(self.to_dict(), indent=indent, ensure_ascii=False)
    
    def save_to_file(self, file_path: str, format: str = "yaml") -> None:
        """
        保存配置到文件
        
        Args:
            file_path: 文件路径
            format: 文件格式 (yaml 或 json)
        """
        file_path = Path(file_path)
        file_path.parent.mkdir(parents=True, exist_ok=True)
        
        if format.lower() == "yaml":
            with open(file_path, 'w', encoding='utf-8') as f:
                yaml.dump(self.to_dict(), f, default_flow_style=False, allow_unicode=True, indent=2)
        elif format.lower() == "json":
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(self.to_json())
        else:
            raise ValueError("格式必须是 'yaml' 或 'json'")


class ConfigManager:
    """配置管理器"""
    
    def __init__(self, config_path: Optional[str] = None, encryption_password: Optional[str] = None):
        """
        初始化配置管理器
        
        Args:
            config_path: 配置文件路径
            encryption_password: 加密密码
        """
        self.config_path = config_path
        self.encryption_password = encryption_password
        self._config: Optional[AppConfig] = None
        self._encryptor: Optional[ConfigEncryption] = None
    
    @property
    def encryptor(self) -> ConfigEncryption:
        """获取加密器"""
        if self._encryptor is None:
            self._encryptor = ConfigEncryption(self.encryption_password)
        return self._encryptor
    
    def load_config(self, config_path: Optional[str] = None) -> AppConfig:
        """
        加载配置文件
        
        Args:
            config_path: 配置文件路径，默认为 src/config/config.yaml
            
        Returns:
            AppConfig: 应用程序配置对象
        """
        # 加载环境变量
        load_dotenv()
        
        # 确定配置文件路径
        if config_path is None:
            config_path = self.config_path or (Path(__file__).parent / "config.yaml")
        else:
            config_path = Path(config_path)
        
        # 读取配置文件
        if config_path.exists():
            with open(config_path, "r", encoding="utf-8") as f:
                if config_path.suffix.lower() in ['.yaml', '.yml']:
                    config_data = yaml.safe_load(f)
                elif config_path.suffix.lower() == '.json':
                    config_data = json.load(f)
                else:
                    raise ValueError(f"不支持的配置文件格式: {config_path.suffix}")
        else:
            config_data = {}
        
        # 处理环境变量替换
        config_data = self._replace_env_vars(config_data)
        
        # 处理加密值解密
        config_data = self._decrypt_sensitive_values(config_data)
        
        # 创建配置对象
        self._config = AppConfig(**config_data)
        return self._config
    
    def get_config(self) -> AppConfig:
        """获取当前配置"""
        if self._config is None:
            return self.load_config()
        return self._config
    
    def reload_config(self) -> AppConfig:
        """重新加载配置"""
        self._config = None
        return self.load_config()
    
    def validate_config(self, config_data: Dict[str, Any]) -> List[str]:
        """
        验证配置数据
        
        Args:
            config_data: 配置数据
            
        Returns:
            验证错误列表
        """
        errors = []
        try:
            AppConfig(**config_data)
        except Exception as e:
            errors.append(str(e))
        return errors
    
    def encrypt_sensitive_config(self, config_path: str, output_path: Optional[str] = None) -> str:
        """
        加密敏感配置
        
        Args:
            config_path: 配置文件路径
            output_path: 输出文件路径
            
        Returns:
            加密文件路径
        """
        return self.encryptor.encrypt_file(config_path, output_path)
    
    def decrypt_sensitive_config(self, encrypted_config_path: str, output_path: Optional[str] = None) -> str:
        """
        解密敏感配置
        
        Args:
            encrypted_config_path: 加密配置文件路径
            output_path: 输出文件路径
            
        Returns:
            解密文件路径
        """
        return self.encryptor.decrypt_file(encrypted_config_path, output_path)
    
    def _replace_env_vars(self, data: Any) -> Any:
        """
        递归替换配置中的环境变量
        
        Args:
            data: 配置数据
            
        Returns:
            替换后的配置数据
        """
        if isinstance(data, dict):
            return {key: self._replace_env_vars(value) for key, value in data.items()}
        elif isinstance(data, list):
            return [self._replace_env_vars(item) for item in data]
        elif isinstance(data, str) and data.startswith("${") and data.endswith("}"):
            # 提取环境变量名
            env_var = data[2:-1]
            default_value = ""
            
            # 支持默认值语法: ${VAR_NAME:default_value}
            if ":" in env_var:
                env_var, default_value = env_var.split(":", 1)
            
            return os.getenv(env_var, default_value)
        else:
            return data
    
    def _decrypt_sensitive_values(self, data: Any) -> Any:
        """
        递归解密配置中的敏感值
        
        Args:
            data: 配置数据
            
        Returns:
            解密后的配置数据
        """
        if isinstance(data, dict):
            return {key: self._decrypt_sensitive_values(value) for key, value in data.items()}
        elif isinstance(data, list):
            return [self._decrypt_sensitive_values(item) for item in data]
        elif isinstance(data, str) and data.startswith("ENC(") and data.endswith(")"):
            # 解密加密的值
            encrypted_value = data[4:-1]
            try:
                return self.encryptor.decrypt(encrypted_value)
            except Exception:
                # 如果解密失败，返回原值
                return data
        else:
            return data


# 全局配置管理器实例
_config_manager = ConfigManager()


def load_config(config_path: Optional[str] = None) -> AppConfig:
    """
    加载配置文件
    
    Args:
        config_path: 配置文件路径，默认为 src/config/config.yaml
        
    Returns:
        AppConfig: 应用程序配置对象
    """
    return _config_manager.load_config(config_path)


def get_config() -> AppConfig:
    """获取当前配置"""
    return _config_manager.get_config()


def reload_config() -> AppConfig:
    """重新加载配置"""
    return _config_manager.reload_config()